package com.yunyao.framework.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yunyao.common.constant.enums.DataDeletedStatus;
import com.yunyao.common.core.BaseContext;
import com.yunyao.common.core.UserInfoRequest;
import com.yunyao.common.dto.supplier.ContractDto;
import com.yunyao.common.exception.BusinessException;
import com.yunyao.common.web.enums.ResultMsgEnum;
import com.yunyao.common.web.util.PageResult;
import com.yunyao.common.web.util.YResult;
import com.yunyao.dao.model.BamuContractContacter;
import com.yunyao.dao.model.BamuContractMaterial;
import com.yunyao.dao.model.BamuContractNodePay;
import com.yunyao.dao.model.BamuContractWirePay;
import com.yunyao.dao.model.BamuPurchaseContract;
import com.yunyao.dao.model.BamuSaleContract;
import com.yunyao.dao.service.bamu.IBamuContractContacterService;
import com.yunyao.dao.service.bamu.IBamuContractMaterialService;
import com.yunyao.dao.service.bamu.IBamuContractNodePayService;
import com.yunyao.dao.service.bamu.IBamuContractWirePayService;
import com.yunyao.dao.service.bamu.IBamuPurchaseContractService;
import com.yunyao.dao.service.bamu.IBamuSaleContractService;
import com.yunyao.framework.dto.contract.*;
import com.yunyao.framework.excel.dto.ContractMaterialExcelImportDto;
import com.yunyao.framework.excel.imports.ContractMaterialExcelImportHandle;
import com.yunyao.framework.service.systemtwo.ContractService;
import com.yunyao.framework.vo.contract.ContractContacterVO;
import com.yunyao.framework.vo.contract.ContractMaterialCountVO;
import com.yunyao.framework.vo.contract.ContractMaterialVO;
import com.yunyao.framework.vo.contract.ContractNodePayVO;
import com.yunyao.framework.vo.contract.ContractWirePayVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.constraints.NotBlank;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author xingjishuai
 * @date 2024-07-15
 */
@Slf4j
@Service
public class ContractServiceImpl implements ContractService {
    @Autowired
    private IBamuSaleContractService ibamuSaleContractService;
    @Autowired
    private IBamuPurchaseContractService iBamuPurchaseContractService;
    @Autowired
    private IBamuContractMaterialService iBamuContractMaterialService;
    @Autowired
    private IBamuContractWirePayService iBamuContractWirePayService;
    @Autowired
    private IBamuContractNodePayService iBamuContractNodePayService;
    @Autowired
    private IBamuContractContacterService iBamuContractContacterService;
    @Autowired
    private ContractMaterialExcelImportHandle contractMaterialExcelImportHandle;
    @Autowired
    private IBamuPurchaseContractService ibamuPurchaseContractService;


    /**
     * 根据合同ID获取合同物料列表
     *
     * @param contractDto 合同查询条件DTO，包含分页信息和合同ID
     * @return YResult<PageResult < ContractMaterialVO>> 包含分页结果的响应对象，数据类型为ContractMaterialVO列表
     */
    @Override
    public YResult<PageResult<ContractMaterialVO>> getContractMaterialList(ContractDto contractDto) {
        // 构建查询条件
        String contractId = contractDto.getContractId();
        LambdaQueryWrapper<BamuContractMaterial> wrapper = new LambdaQueryWrapper<BamuContractMaterial>()
                .eq(StringUtils.isNotBlank(contractId),BamuContractMaterial::getContractId, contractId)
                .in(CollectionUtils.isNotEmpty(contractDto.getContractMaterialIdList()), BamuContractMaterial::getContractMaterialId, contractDto.getContractMaterialIdList())
                .eq(BamuContractMaterial::getIsDeleted, DataDeletedStatus.NO.getType())
                .orderByAsc(BamuContractMaterial::getMaterialSortNum)
                .orderByAsc(BamuContractMaterial::getId);
        // 分页查询
        IPage<BamuContractMaterial> payPage = new Page<>(contractDto.getPageIndex(), contractDto.getPageSize());
        payPage = iBamuContractMaterialService.page(payPage, wrapper);

        // 处理查询结果
        if (CollectionUtils.isEmpty(payPage.getRecords())) {
            return YResult.success(new PageResult<>());
        }

        // 转换为VO对象列表
        List<ContractMaterialVO> materialVOList = materialDaoToVoList(payPage.getRecords());

        // 返回分页结果
        return YResult.success(new PageResult<>(materialVOList, payPage.getCurrent(), payPage.getSize(), payPage.getPages(), payPage.getTotal()));
    }


    private List<ContractMaterialVO> materialDaoToVoList(List<BamuContractMaterial> records) {
        return records.stream().map(this::materialDaoToVo).collect(Collectors.toList());
    }

    private ContractMaterialVO materialDaoToVo(BamuContractMaterial bamuContractMaterial) {
        ContractMaterialVO contractMaterialVO = new ContractMaterialVO();
        BeanUtils.copyProperties(bamuContractMaterial, contractMaterialVO);
        return contractMaterialVO;
    }

    /**
     * 根据合同ID获取电汇支付信息
     * 此方法首先通过合同ID查询相应的电汇支付记录如果找不到对应的电汇支付记录，则返回错误结果；
     * 否则，将电汇支付记录转换为指定的VO对象，并返回成功结果
     *
     * @param contractDto 合同数据传输对象，包含合同ID等信息
     * @return YResult对象，包含操作结果和可能的电汇支付信息
     */
    @Override
    public YResult<ContractWirePayVO> getWirePayInfo(ContractDto contractDto) {
        // 从合同DTO中提取合同ID
        String contractId = contractDto.getContractId();
        // 通过合同ID查询电汇支付信息
        BamuContractWirePay bamuContractWirePay =
                iBamuContractWirePayService.getByContractId(contractId);
        // 如果找不到对应的电汇支付记录，返回错误结果
        if (Objects.isNull(bamuContractWirePay)) {
            return YResult.success();
        }
        // 将电汇支付记录转换为ContractWirePayVO对象
        ContractWirePayVO contractWirePayVO = wirePayDaoToVo(bamuContractWirePay);
        // 返回成功结果，包含转换后的电汇支付信息
        return YResult.success(contractWirePayVO);
    }

    private ContractWirePayVO wirePayDaoToVo(BamuContractWirePay bamuContractWirePay) {
        ContractWirePayVO contractWirePayVO = new ContractWirePayVO();
        BeanUtils.copyProperties(bamuContractWirePay, contractWirePayVO);
        return contractWirePayVO;
    }

    /**
     * 根据合同ID查询合同节点支付列表
     *
     * @param contractDto 合同查询条件对象，包含分页信息和合同ID
     * @return 返回查询结果，包括节点支付信息列表和分页数据
     */
    @Override
    public YResult<PageResult<ContractNodePayVO>> getContractNodePayList(ContractDto contractDto) {
        // 提取合同ID作为查询条件
        String contractId = contractDto.getContractId();
        // 构建查询条件，筛选未被删除且关联当前合同的节点支付记录
        LambdaQueryWrapper<BamuContractNodePay> wrapper = new LambdaQueryWrapper<BamuContractNodePay>()
                .eq(BamuContractNodePay::getContractId, contractId)
                .eq(BamuContractNodePay::getIsDeleted, DataDeletedStatus.NO.getType());
        // 执行分页查询
        IPage<BamuContractNodePay> payPage = new Page<>(contractDto.getPageIndex(), contractDto.getPageSize());
        payPage = iBamuContractNodePayService.page(payPage, wrapper);

        // 若查询结果为空，直接返回空的分页结果
        if (CollectionUtils.isEmpty(payPage.getRecords())) {
            return YResult.success(new PageResult<>());
        }

        // 将查询结果转换为前端展示的VO对象列表
        List<ContractNodePayVO> nodePayVOList = nodePayDaoToVoList(payPage.getRecords());

        // 返回包含数据的分页结果
        return YResult.success(new PageResult<>(nodePayVOList, payPage.getCurrent(), payPage.getSize(), payPage.getPages(), payPage.getTotal()));
    }


    @Override
    public BamuContractNodePay findByContractIdStatus(@NotBlank String contractId, @NotBlank String nodeType) {
        return iBamuContractNodePayService.lambdaQuery()
                .eq(BamuContractNodePay::getContractId, contractId)
                .eq(BamuContractNodePay::getIsDeleted, 0)
                .eq(BamuContractNodePay::getNodeType, nodeType)
                .orderByDesc(BamuContractNodePay::getCreatedAt)
                .last("limit 1")
                .one();
    }


    /**
     * 保存材料信息
     *
     * @param saveDto 包含要保存的材料信息的Dto对象
     * @return 操作结果，包括成功与否和相关消息
     */
    @Override
    public YResult<String> saveMaterialInfo(ContractMaterialSaveDto saveDto) {
        String contractId = saveDto.getContractId();
        // 获取待保存的材料信息列表
        List<ContractMaterialInfoSaveDto> dtoList = saveDto.getSaveDtoList();
        // 如果列表为空，则返回参数错误结果
        if (CollectionUtils.isEmpty(dtoList)) {
            return YResult.error(ResultMsgEnum.PARAM_ERROR);
        }
        // 将Dto列表转换为Dao对象列表
        List<BamuContractMaterial> daoList = materialDtoToDaoList(dtoList);
        // 如果转换后的列表为空，则返回参数错误结果
        if (CollectionUtils.isEmpty(daoList)) {
            return YResult.error(ResultMsgEnum.PARAM_ERROR);
        }
        // 批量保存或更新材料信息
        iBamuContractMaterialService.saveOrUpdateBatch(daoList, 20);
        // 更新合同材料数量（具体实现略）
        updateContractMaterialCount(contractId);
        // 返回成功结果，包括合同ID
        return YResult.success(saveDto.getContractId());
    }

    private List<BamuContractMaterial> materialDtoToDaoList(List<ContractMaterialInfoSaveDto> dtoList) {
        return dtoList.stream().map(this::materialDtoToDao).collect(Collectors.toList());
    }

    private BamuContractMaterial materialDtoToDao(ContractMaterialInfoSaveDto contractMaterialInfoSaveDto) {
        BamuContractMaterial bamuContractMaterial = new BamuContractMaterial();
        BeanUtils.copyProperties(contractMaterialInfoSaveDto, bamuContractMaterial);
        return bamuContractMaterial;
    }

    /**
     * 保存或更新支付信息
     * 该方法接收一个包含支付信息的数据传输对象，并将其属性复制到支付实体中，随后保存或更新该实体
     * 此外，它还将处理相关的节点支付信息，如果有提供的话
     *
     * @param saveDto 包含支付信息和相关节点支付信息的数据传输对象
     * @return 包含操作结果的YResult对象，如果成功，则返回操作的合同ID
     */
    @Override
    public YResult<String> savePayInfo(ContractWirePaySaveDto saveDto) {
        try {
            checkSavePayInfo(saveDto);
            // 创建支付实体对象，并将数据传输对象的属性复制到支付实体
            BamuContractWirePay contractWirePay = new BamuContractWirePay();
            BeanUtils.copyProperties(saveDto, contractWirePay);
            // 保存或更新支付实体
            iBamuContractWirePayService.saveOrUpdate(contractWirePay);

            // 将节点支付数据传输对象列表转换为节点支付实体列表
            List<BamuContractNodePay> nodePayDtoToDaoList =
                    nodePayDtoToDaoList(saveDto.getNodePaySaveDtoList());
            // 如果节点支付实体列表不为空，则批量保存或更新这些实体
            if (CollectionUtils.isNotEmpty(nodePayDtoToDaoList)) {
                iBamuContractNodePayService.saveOrUpdateBatch(nodePayDtoToDaoList);
            }
            // 返回操作成功的结果，包含合同ID
            return YResult.success(saveDto.getContractId());
        } catch (BusinessException be) {
            log.warn("保存支付信息失败 {}", be.getMessage());
            return YResult.error(be.getMessage());
        } catch (Exception ex) {
            log.error("保存支付信息失败 {}", ex.getMessage());
            return YResult.error(ex.getMessage());
        }
    }


    private void checkSavePayInfo(ContractWirePaySaveDto saveDto) {
        String id = saveDto.getId();
        if (StringUtils.isBlank(id)) {
            String contractId = saveDto.getContractId();
            if (StringUtils.isBlank(contractId)) {
                throw new BusinessException("新增支付节点合同id不能为空");
            }
            BamuContractWirePay bamuContractWirePay =
                    iBamuContractWirePayService.getByContractId(contractId);
            if (Objects.nonNull(bamuContractWirePay)) {
                throw new BusinessException(String.format("新增支付节点合同id{ %s }已存在支付节点不能重复新增",
                        contractId));
            }
            String priceType = saveDto.getPriceType();
            if (StringUtils.isBlank(priceType)) {
                throw new BusinessException("价格类型不能为空");
            }
            String paymentCycle = saveDto.getPaymentCycle();
            if (StringUtils.isBlank(paymentCycle)) {
                throw new BusinessException("付款周期不能为空");
            }
            List<ContractNodePaySaveDto> nodePaySaveDtoList = saveDto.getNodePaySaveDtoList();
            if (CollectionUtils.isEmpty(nodePaySaveDtoList)) {
                throw new BusinessException("付款节点不能为空");
            }
        }
    }

    /**
     * 根据合同ID获取联系人列表
     *
     * @param contractId 合同的唯一标识
     * @return 包含联系人信息的结果对象，联系人信息以List形式返回
     */
    @Override
    public YResult<List<ContractContacterVO>> getContacterList(String contractId) {
        // 检查合同ID是否为空，为空则返回参数错误结果
        if (StringUtils.isEmpty(contractId)) {
            return YResult.error(ResultMsgEnum.PARAM_ERROR);
        }
        // 构建查询条件，筛选未被删除且合同ID匹配的联系人
        LambdaQueryWrapper<BamuContractContacter> queryWrapper =
                new LambdaQueryWrapper<BamuContractContacter>()
                        .eq(BamuContractContacter::getContractId, contractId)
                        .eq(BamuContractContacter::getIsDeleted, DataDeletedStatus.NO.getType());
        // 执行查询，获取联系人列表
        List<BamuContractContacter> contacterList =
                iBamuContractContacterService.list(queryWrapper);
        // 如果列表为空，返回空的联系人列表
        if (CollectionUtils.isEmpty(contacterList)) {
            return YResult.success(Lists.newArrayList());
        }
        // 将查询到的联系人信息转换为VO类型，并返回成功结果
        return YResult.success(contacterDaoToVoList(contacterList));
    }

    /**
     * 保存或更新联系人信息
     *
     * @param saveDto 包含联系人信息的数据传输对象
     * @return 返回一个包含操作结果的泛型对象，成功时携带合同ID
     */
    @Override
    public YResult<String> saveContacterInfo(ContractContacterSaveDto saveDto) {
        BamuContractContacter oldContacter = iBamuContractContacterService.getByPhoneAndName(saveDto.getContractId(), saveDto.getPhone(), saveDto.getName());
        if (Objects.nonNull(oldContacter)) {
            return YResult.error("联系人信息已存在，不能重复添加");
        }
        // 将数据传输对象的属性复制到联系人实体对象
        BamuContractContacter bamuContractContacter = contacterDtoToDao(saveDto);
        // 调用服务保存或更新联系人信息
        iBamuContractContacterService.saveOrUpdate(bamuContractContacter);
        // 返回成功结果，携带合同ID
        return YResult.success(saveDto.getContractId());
    }


    /**
     * 保存或更新联系人信息
     *
     * @param saveDtos 包含联系人信息的数据传输对象
     * @return 返回一个包含操作结果的泛型对象，成功时携带合同ID
     */
    @Override
    public YResult<String> saveContacterInfoBatch(List<ContractContacterSaveDto> saveDtos) {
        // 检查保存的联系人信息列表是否为空，如果是，抛出业务异常
        if (CollectionUtils.isEmpty(saveDtos)) {
            throw new BusinessException("保存的联系人信息列表不能为空");
        }
        List<BamuContractContacter> saveList = new ArrayList<>(saveDtos.size());
        // 遍历保存的联系人信息列表，逐个处理
        for (ContractContacterSaveDto saveDto : saveDtos) {
            if (Objects.nonNull(iBamuContractContacterService.getByPhoneAndName(saveDto.getContractId(), saveDto.getPhone(), saveDto.getName()))) {
                continue;
            }
            // 将数据传输对象的属性复制到联系人实体对象
            BamuContractContacter bamuContractContacter = contacterDtoToDao(saveDto);
            saveList.add(bamuContractContacter);
        }
        if (!CollectionUtils.isEmpty(saveList)) {
            iBamuContractContacterService.saveOrUpdateBatch(saveList, 20);
            // 返回成功结果，携带合同ID
            return YResult.success(saveDtos.get(0).getContractId());
        }
        return YResult.success("");
    }

    private BamuContractContacter contacterDtoToDao(ContractContacterSaveDto contractContacterSaveDto) {
        BamuContractContacter bamuContractContacter = new BamuContractContacter();
        bamuContractContacter.setContractId(contractContacterSaveDto.getContractId());
        bamuContractContacter.setIsDeleted(DataDeletedStatus.NO.getType());
        bamuContractContacter.setName(contractContacterSaveDto.getName());
        bamuContractContacter.setPhone(contractContacterSaveDto.getPhone());

        return bamuContractContacter;
    }


    /**
     * 删除联系人信息
     *
     * @param id 联系人ID
     * @return 删除操作的结果，包含操作成功的标识和联系人ID
     */
    @Override
    public YResult<String> deletedContacterInfo(String id) {
        // 创建一个新的联系人对象，用于更新联系人的删除状态
        BamuContractContacter bamuContractContacter = new BamuContractContacter();
        bamuContractContacter.setId(id); // 设置联系人ID
        bamuContractContacter.setIsDeleted(DataDeletedStatus.YES.getType()); // 标记联系人为已删除状态

        // 调用服务更新联系人的删除状态
        iBamuContractContacterService.updateById(bamuContractContacter);

        // 返回删除成功的结果，包含操作成功的标识和联系人ID
        return YResult.success(id);
    }

    /**
     * 批量删除合同物料信息
     *
     * @param deletedDto 包含待删除合同物料ID列表的DTO对象
     * @return 删除操作的结果，包括成功与否和相关消息
     */
    @Override
    public YResult<String> deletedMaterialInfo(ContractMaterialDeletedDto deletedDto) {
        // 检查提供的ID列表是否为空，如果为空则返回参数错误的结果
        if (CollectionUtils.isEmpty(deletedDto.getIdList())) {
            return YResult.error(ResultMsgEnum.PARAM_ERROR);
        }

        // 初始化一个列表，用于存储即将更新的合同物料对象
        List<BamuContractMaterial> updateList = Lists.newArrayList();

        // 遍历待删除的合同物料ID列表，创建并添加对应的BamuContractMaterial对象到更新列表中
        for (String id : deletedDto.getIdList()) {
            BamuContractMaterial contractMaterial = new BamuContractMaterial();
            contractMaterial.setId(id);
            contractMaterial.setIsDeleted(DataDeletedStatus.YES.getType());
            updateList.add(contractMaterial);
        }

        // 调用服务层方法，批量更新合同物料的删除状态
        iBamuContractMaterialService.updateBatchById(updateList, 20);

        // 返回删除成功的结果，携带被删除合同的ID
        return YResult.success(deletedDto.getContractId());
    }

    /**
     * 批量导入物料信息
     * <p>
     * 此方法主要用于从Excel文件中导入物料信息到系统中它首先解析上传的文件，
     * 获取物料数据，然后将这些数据转换为系统可以存储的对象最后，批量保存这些
     * 物料信息到数据库中
     *
     * @param importDto 包含合同ID和物料文件的导入数据传输对象
     * @return YResult对象，包含导入结果信息如果导入成功，返回成功的YResult对象和合同ID；
     * 如果导入失败，返回失败的YResult对象和错误信息
     */
    @Override
    public YResult<String> importMaterial(ContractMaterialImportDto importDto) {
        try {
            // 获取合同ID，用于后续将导入的物料信息关联到对应的合同上
            String contractId = importDto.getContractId();
            // 从导入数据传输对象中获取文件
            MultipartFile file = importDto.getFile();
            if (file == null) {
                return YResult.error(ResultMsgEnum.IMPORT_FILE_NOT_FOUND);
            }

            // 验证文件大小
            long maxSize = 1024 * 1024 * 50;
            // 表示文件的最大允许大小为50MB (1024 * 1024 * 50 字节)
            if (file.getSize() > maxSize) {
                return YResult.error(ResultMsgEnum.IMPORT_FILE_SIZE_ERROR);
            }

            // 解析文件，将Excel中的物料信息转换为系统能够处理的DTO列表
            List<ContractMaterialExcelImportDto> importDtoList =
                    contractMaterialExcelImportHandle.importContractMaterialExcel(file);

            // 检查解析结果，如果没有数据，则返回错误提示
            if (CollectionUtils.isEmpty(importDtoList)) {
                return YResult.error(ResultMsgEnum.IMPORT_NO_DATA);
            }

            // 将解析后的DTO列表和合同ID转换为数据库访问对象（DAO）列表
            List<BamuContractMaterial> daoList = importDtoToDaoList(importDtoList, contractId);

            // 批量保存物料信息到数据库
            iBamuContractMaterialService.saveBatch(daoList, 100);

            // 返回导入成功的提示信息和合同ID
            return YResult.success(contractId);
        } catch (BusinessException e) {
            log.warn("导入业务异常 ", e);
            return YResult.error(e.getMessage());
        } catch (IllegalArgumentException e) {
            log.error("Invalid argument provided: ", e);
            return YResult.error(ResultMsgEnum.IMPORT_INVALID_ARGUMENT);
        } catch (Exception e) {
            log.error("Unexpected error during import process: ", e);
            return YResult.error(ResultMsgEnum.IMPORT_UNEXPECTED_ERROR);
        }
    }

    /**
     * 处理节点付费删除请求
     * <p>
     * 本方法通过从数据库中检索特定的付费节点信息来处理删除请求如果找到相应的记录，
     * 它会将该记录标记为已删除状态，并更新数据库中的信息如果未找到记录，
     * 则返回一个错误结果
     *
     * @param deletedDto 包含要删除的节点付费信息的DTO，特别是节点ID
     * @return 返回一个YResult对象，其中包含处理结果如果操作成功，结果对象将包含被删除节点的ID；
     * 如果操作失败或未找到节点信息，将返回一个包含错误信息的结果对象
     */
    @Override
    public YResult<String> nodePayDeleted(ContractNodePayDeletedDto deletedDto) {
        // 根据提供的ID检索节点付费信息，确保该信息未被标记为已删除
        BamuContractNodePay contractNodePay =
                iBamuContractNodePayService.getByIdAndIsDeleted(deletedDto.getId());

        // 如果未找到相应的付费信息，返回一个错误结果
        if (Objects.isNull(contractNodePay)) {
            return YResult.error(ResultMsgEnum.PARAM_ERROR);
        }

        // 将找到的付费信息标记为已删除状态
        contractNodePay.setIsDeleted(DataDeletedStatus.YES.getType());

        // 更新数据库中的付费信息
        iBamuContractNodePayService.updateById(contractNodePay);

        // 返回一个成功结果，包含被删除节点的ID
        return YResult.success(deletedDto.getId());
    }

    /**
     * 根据合同ID获取合同材料的总数和总价格
     *
     * @param contractDto 合同数据传输对象，包含合同ID等信息
     * @return YResult对象，包含操作结果或错误信息，以及ContractMaterialCountVO对象（如果操作成功）
     */
    @Override
    public YResult<ContractMaterialCountVO> getContractMaterialCount(ContractDto contractDto) {
        try {
            // 提取合同ID
            String contractId = contractDto.getContractId();
            // 校验合同ID是否为空
            if (StringUtils.isBlank(contractId)) {
                return YResult.error(ResultMsgEnum.PARAM_ERROR);
            }
            // 更新合同材料数量（具体实现略）
            updateContractMaterialCount(contractId);
            // 初始化合同材料计数对象
            ContractMaterialCountVO contractMaterialCountVO = new ContractMaterialCountVO();
            // 获取合同材料总数
            BigDecimal totalNum = iBamuContractMaterialService.getTotalNumByContractId(contractId);
            // 获取合同材料总价格
            BigDecimal totalPrice =
                    iBamuContractMaterialService.getTotalPriceByContractId(contractId);
            // 设置总数和总价格到VO对象
            contractMaterialCountVO.setTotalNum(totalNum);
            contractMaterialCountVO.setTotalPrice(totalPrice);
            // 返回成功结果
            return YResult.success(contractMaterialCountVO);
        } catch (Exception ex) {
            // 捕获异常，返回系统错误信息
            return YResult.error(ResultMsgEnum.SYS_ERROR);
        }
    }


    /**
     * 更新进销存合同的总价和数量
     * 根据合同ID查询是否存在销售或采购合同，并更新其总价和数量
     *
     * @param contractId 合同ID，用于查询具体的销售或采购合同
     */
    private void updateContractMaterialCount(String contractId) {
        // 根据合同ID查询销售合同，不包括已删除的记录
        BamuSaleContract bamuSaleContract = ibamuSaleContractService.getByIdNoDelete(contractId);
        // 如果找到了对应的销售合同
        if (Objects.nonNull(bamuSaleContract)) {
            // 更新销售合同的总价和数量
            ibamuSaleContractService.updateTotalPriceAndNumByContractId(contractId);
            ibamuSaleContractService.updateTotalRealPriceAndNumByContractId(contractId);
            return;
        }
        // 如果未找到销售合同，则尝试查询采购合同
        BamuPurchaseContract bamuPurchaseContract = iBamuPurchaseContractService.getByIdNoDelete(contractId);
        // 如果找到了对应的采购合同
        if (Objects.isNull(bamuPurchaseContract)) {
            return;
        }
        // 更新采购合同的总价和数量
        iBamuPurchaseContractService.updateTotalPriceAndNumByContractId(contractId);
    }

    /**
     * 将导入的DTO对象列表转换为持久层对象列表
     * 本方法解释了为什么需要进行转换：为了将外部数据导入到数据库中，我们需要先将这些数据转换为数据库层可以理解的格式
     *
     * @param importDtoList 从Excel导入的合同材料DTO列表
     * @param contractId    合同ID，用于关联导入材料的合同信息
     * @return 返回转换后的持久层对象列表
     */
    private List<BamuContractMaterial> importDtoToDaoList(List<ContractMaterialExcelImportDto> importDtoList, String contractId) {
        return importDtoList.stream()
                .map(x -> importDtoToDao(x, contractId))
                .collect(Collectors.toList());
    }


    /**
     * 将Excel导入的材料信息DTO转换为数据库实体
     * <p>
     * 此方法负责将用户从Excel文件中导入的材料数据转换为数据库中使用的实体对象
     * 它提取材料的相关信息，并将其映射到数据库实体的属性上
     *
     * @param excelImportDto 从Excel导入的材料信息数据传输对象
     * @param contractId     合同ID，用于将材料信息关联到特定的合同
     * @return 返回填充了材料信息的数据库实体对象
     */
    private BamuContractMaterial importDtoToDao(ContractMaterialExcelImportDto excelImportDto,
                                                String contractId) {
        // 获取当前用户信息，用于后续设置租户ID等信息
        UserInfoRequest userInfo = BaseContext.getUserInfo();

        // 初始化数据库实体对象
        BamuContractMaterial bamuContractMaterial = new BamuContractMaterial();

        // 设置合同ID，将材料信息与特定合同关联起来
        bamuContractMaterial.setContractId(contractId);

        // 以下代码将DTO中的材料信息映射到数据库实体的相应属性上
        bamuContractMaterial.setMaterialId(excelImportDto.getMaterialId());
        bamuContractMaterial.setMaterialCode(excelImportDto.getMaterialCode());
        bamuContractMaterial.setMaterialName(excelImportDto.getMaterialName());
        bamuContractMaterial.setMaterialSpecs(excelImportDto.getMaterialSpecs());
        bamuContractMaterial.setMaterialModel(excelImportDto.getMaterialModel());
        bamuContractMaterial.setMaterialUnit(excelImportDto.getMaterialUnit());
        bamuContractMaterial.setMaterialBrand(excelImportDto.getMaterialBrand());
        bamuContractMaterial.setMaterialNum(excelImportDto.getMaterialNum());
        bamuContractMaterial.setMaterialTaxCode(excelImportDto.getMaterialTaxCode());
        bamuContractMaterial.setMaterialTaxShortName(excelImportDto.getMaterialTaxShortName());
        bamuContractMaterial.setExcludingTaxUnitPrice(excelImportDto.getExcludingTaxUnitPrice());
        bamuContractMaterial.setTax(excelImportDto.getTax());
        bamuContractMaterial.setIncludingTaxUnitPrice(excelImportDto.getIncludingTaxUnitPrice());
        bamuContractMaterial.setIncludingTaxTotalPrice(excelImportDto.getIncludingTaxTotalPrice());
        bamuContractMaterial.setMaterialMark(excelImportDto.getMaterialMark());

        // 设置租户ID，用于支持多租户环境下数据的隔离
        bamuContractMaterial.setTenantId(userInfo.getTenantId());

        // 以下属性设置是否新增、材料排序等信息，用于数据库中的逻辑处理
        bamuContractMaterial.setIsAdd(excelImportDto.getIsAdd());
        bamuContractMaterial.setMaterialSortNum(excelImportDto.getMaterialSortNum());

        // 返回填充完毕的数据库实体对象
        return bamuContractMaterial;
    }


    /**
     * 将合同联系人DAO对象列表转换为VO对象列表
     * <p>
     * 此方法接收一个合同联系人的DAO对象列表作为参数，将其转换为VO对象列表并返回如果输入列表为空，
     * 则返回一个空的VO对象列表这种方法使用Java 8的Stream API进行转换，提高了代码的可读性和简洁性
     *
     * @param contacterList 合同联系人的DAO对象列表
     * @return 转换后的VO对象列表
     */
    private List<ContractContacterVO> contacterDaoToVoList(List<BamuContractContacter> contacterList) {
        // 检查输入列表是否为空，如果为空则直接返回一个新的空列表
        if (CollectionUtils.isEmpty(contacterList)) {
            return Lists.newArrayList();
        }
        // 使用Stream API对列表进行转换，每个元素都调用contacterDaoToVo方法转换为VO对象
        return contacterList.stream().map(this::contacterDaoToVo).collect(Collectors.toList());
    }

    /**
     * 将数据访问对象（DAO）层的联系人信息转换为视图对象（VO）层的联系人信息
     * 此方法主要用于数据格式的转换，确保联系人信息能够在不同的层之间正确传递和使用
     *
     * @param bamuContractContacter 数据访问对象层的联系人信息，包含从数据库等数据源获取的原始联系人数据
     * @return ContractContacterVO 视图对象层的联系人信息，用于前端展示或其他业务逻辑处理
     */
    private ContractContacterVO contacterDaoToVo(BamuContractContacter bamuContractContacter) {
        ContractContacterVO contractContacterVO = new ContractContacterVO();
        BeanUtils.copyProperties(bamuContractContacter, contractContacterVO);
        return contractContacterVO;
    }

    private List<BamuContractNodePay> nodePayDtoToDaoList(List<ContractNodePaySaveDto> nodePaySaveDtoList) {
        if (CollectionUtils.isEmpty(nodePaySaveDtoList)) {
            return Lists.newArrayList();
        }
        return nodePaySaveDtoList.stream().map(this::nodePayDtoToDao).collect(Collectors.toList());
    }

    private BamuContractNodePay nodePayDtoToDao(ContractNodePaySaveDto contractNodePaySaveDto) {
        BamuContractNodePay bamuContractNodePay = new BamuContractNodePay();
        BeanUtils.copyProperties(contractNodePaySaveDto, bamuContractNodePay);
        return bamuContractNodePay;
    }

    private List<ContractNodePayVO> nodePayDaoToVoList(List<BamuContractNodePay> records) {
        if (CollectionUtils.isEmpty(records)) {
            return Lists.newArrayList();
        }
        return records.stream().map(this::nodePayDaoToVo).collect(Collectors.toList());
    }

    private ContractNodePayVO nodePayDaoToVo(BamuContractNodePay bamuContractNodePay) {
        ContractNodePayVO contractNodePayVO = new ContractNodePayVO();
        BeanUtils.copyProperties(bamuContractNodePay, contractNodePayVO);
        return contractNodePayVO;
    }

}
